require 'drb'
require 'milfs/object'
require 'milfs/fs'

module Mil
  module Service
    class Storage
      include DRb::DRbUndumped

      def initialize(path, blocksize=nil)
	@object_store = Mil::Object::Store.new(path)

	@block_gen = blocksize ? Mil::FS::BlockGenerator.new(blocksize) : Mil::FS::BlockGenerator.new
      end

      def store(file)
	blocks = @block_gen.to_blocks(file.contents)
	
	block_addrs = blocks.collect { |b|
	  @object_store.store(b)
	}

	unless blocks.size == block_addrs.size
	  block_addrs.each { |b|
	    @object_store.dereference(b)
	  }

	  raise StandardError, "Failed to store all blocks of the passed contents"
	end

	block_list = Mil::FS::BlockList.new(block_addrs)
	block_list_addr = @object_store.store(block_list)

	node = Mil::FS::FileNode.new(block_list_addr)
	node.created = file.created
	node.updated = file.updated ? file.updated : file.created
	node.accessed = file.accessed ? file.accessed : file.created
	node.revision = file.node

	file.node = @object_store.store(node)

	file
      end

      def retrieve(addr)
	puts "retrieving #{add}"
	file = Mil::FS::File.new

	node = @object_store.fetch(addr)

	unless node.is_a? Mil::FS::FileNode
	  raise StandardError, "Expected to retrieve a FileNode from object store but got #{node.class}"
	end

	file.node = addr
	file.revision = node.revision
	file.created = node.created
	file.updated = node.updated
	file.accessed = node.accessed

	block_list = @object_store.fetch(node.block_list)

	blocks = block_list.blocks.collect { |b|
	  @object_store.fetch(b)
	}

	unless blocks.size == block_list.blocks.size
	  raise StandardError, "Failed to store all blocks of the passed contents"
	end

	file.contents = @block_gen.to_stream(blocks).read

	puts "got #{file.node} of size #{file.contents.size}"

	file
      end

      def exist?(addr)
	@boject_store.exist? addr
      end

      def delete(file)
	@object_store.dereference(file.node)
      end
    end
  end
end
